#include "Aggregate.h"
#include <stdio.h>

CAggregateFactory AggregateFactory;

//////////////////////////////////////////////////////////////////
//  CAggregate
//////////////////////////////////////////////////////////////////

CAggregate::CAggregate() : m_dwRefCnt(0)
{
    m_lpIUnknownOuter = &m_xTheUnknown;
    AggregateFactory.LockServer(TRUE);
}

CAggregate::CAggregate(IUnknown* lpIUnknownOuter)
{
    m_lpIUnknownOuter = lpIUnknownOuter;
    AggregateFactory.LockServer(TRUE);
}

CAggregate::~CAggregate()
{
    AggregateFactory.LockServer(FALSE);
}

ULONG __stdcall CAggregate::XProxy::AddRef()
{
    METHOD_PROLOGUE(CAggregate, Proxy);
    return pThis->m_lpIUnknownOuter->AddRef();
}

ULONG __stdcall CAggregate::XProxy::Release()
{
    METHOD_PROLOGUE(CAggregate, Proxy);
    return pThis->m_lpIUnknownOuter->Release();
}

HRESULT __stdcall CAggregate::XProxy::QueryInterface(REFIID iid, void** ppvObj)
{
    METHOD_PROLOGUE(CAggregate, Proxy);
    return pThis->m_lpIUnknownOuter->QueryInterface(iid, ppvObj);
}

HRESULT __stdcall CAggregate::XProxy::AggregateTest()
{
    printf("CAggregate::Test\r\n");
    return S_OK;
}

ULONG __stdcall CAggregate::XTheUnknown::AddRef()
{
    METHOD_PROLOGUE(CAggregate, TheUnknown);
    pThis->m_dwRefCnt++;
    return pThis->m_dwRefCnt;
}

ULONG __stdcall CAggregate::XTheUnknown::Release()
{
    METHOD_PROLOGUE(CAggregate, TheUnknown);

    if (pThis->m_dwRefCnt > 0)
        pThis->m_dwRefCnt--;

    if (pThis->m_dwRefCnt == 0)
    {
        printf("Release CAggregate\r\n");
        delete pThis;
    }
    return pThis->m_dwRefCnt;
}

HRESULT __stdcall CAggregate::XTheUnknown::QueryInterface(REFIID iid, void** ppvObj)
{
    METHOD_PROLOGUE(CAggregate, TheUnknown);

    if (!ppvObj)
        return E_POINTER;

    *ppvObj = nullptr;

    if (iid == IID_IUnknown)
    {
        *ppvObj = this;
    }
    else if (iid == IID_IAggregate)
    {
        *ppvObj = &(pThis->m_xProxy);
    }

    if (*ppvObj)
    {
        ((IUnknown*)(*ppvObj))->AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}


//////////////////////////////////////////////////////////////////
//  CAggregateFactory
//////////////////////////////////////////////////////////////////

CAggregateFactory::CAggregateFactory()
{
}

CAggregateFactory::~CAggregateFactory()
{
}

HRESULT __stdcall CAggregateFactory::CreateInstance(
    IN OPTIONAL IUnknown* pUnkOuter, 
    IN REFIID riid, 
    OUT void** ppvObject
)
{
    if (!pUnkOuter)
    {
        CAggregate* lpAggregate = new CAggregate;
        return lpAggregate->m_xProxy.QueryInterface(riid, ppvObject);
    }
    else if (pUnkOuter)
    {
        CAggregate* lpAggregate = new CAggregate(pUnkOuter);
        return lpAggregate->m_xTheUnknown.QueryInterface(riid, ppvObject);
    }

    return S_OK;
}

HRESULT __stdcall CAggregateFactory::LockServer(IN BOOL fLock)
{
    if (fLock)
    {
        InterlockedIncrement(&m_nLockTick);
    }
    else
    {
        if (m_nLockTick > 0)
            InterlockedDecrement(&m_nLockTick);
    }

    return S_OK;
}
